package com.google.code.sms.domain;

import java.util.Comparator;

/**
 * Comparator for sorting media files.
 */
public class MediaElementComparator implements Comparator<MediaElement> {

    @Override
    public int compare(MediaElement a, MediaElement b) {

        // Directories before files.
        if (!a.isDirectory() && b.isDirectory()) 
        {
            return 1;
        }
        if (a.isDirectory() && !b.isDirectory()) 
        {
            return -1;
        }

        // Root directories before media directories.
        if (a.isMediaDirectory() && b.isRootDirectory())
        {
           return 1;
        }
        if (a.isRootDirectory() && b.isMediaDirectory())
        {
            return -1;
        }
          
        // Sort media directories by year
        if (a.isMediaDirectory() && b.isMediaDirectory())
        {
            int i = nullSafeCompare(a.getMetaData().getYear(), b.getMetaData().getYear(), false);
            if (i != 0)
            {
                return i;
            }
        }
        
        if (a.isDirectory() && b.isDirectory())
        { 
            return a.getName().compareToIgnoreCase(b.getName());
        }

        // Compare by disc and track numbers, if present.
        Integer trackA = getSortableDiscAndTrackNumber(a);
        Integer trackB = getSortableDiscAndTrackNumber(b);
        int i = nullSafeCompare(trackA, trackB, false);
        if (i != 0) {
            return i;
        }

        return a.getPath().compareToIgnoreCase(b.getPath());
    }

    private <T extends Comparable<T>> int nullSafeCompare(T a, T b, boolean nullIsSmaller) {
        if (a == null && b == null) {
            return 0;
        }
        if (a == null) {
            return nullIsSmaller ? -1 : 1;
        }
        if (b == null) {
            return nullIsSmaller ? 1 : -1;
        }
        return a.compareTo(b);
    }

    private Integer getSortableDiscAndTrackNumber(MediaElement element) {
        if (element.getMetaData().getTrackNumber() == null) {
            return null;
        }

        int discNumber = element.getMetaData().getDiscNumber() == null ? 1 : element.getMetaData().getDiscNumber();
        return discNumber * 1000 + element.getMetaData().getTrackNumber();
    }
}
